package com.jrx.anytxn.param;

import com.jcraft.jsch.Channel;
import com.jcraft.jsch.ChannelExec;
import com.jcraft.jsch.ChannelSftp;
import com.jcraft.jsch.JSch;
import com.jcraft.jsch.JSchException;
import com.jcraft.jsch.Session;
import com.jcraft.jsch.SftpException;
import org.apache.commons.compress.archivers.tar.TarArchiveEntry;
import org.apache.commons.compress.archivers.tar.TarArchiveInputStream;
import org.springframework.util.StopWatch;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.zip.GZIPInputStream;

/**
 * AnyAPI应用部署
 */
public class ApiAppDeploy {

    //  环境账号和密码
    public static Map<String, String> apMap = new HashMap<>();

    static {
        apMap.put("branch", "ccs&Xib@88888888");
        apMap.put("trunk", "ccs&Abcd@1234");
    }

    //  环境账号和密码
    public static Map<String, List<String>> hostMap = new HashMap<>();

    static {
        // branch
        //hostMap.put("branch-anyapi-server-api", Arrays.asList("10.71.142.21", "10.71.141.91"));
        hostMap.put("branch-anyapi-server-api", Arrays.asList("10.71.136.47", "10.71.137.158"));
        hostMap.put("branch-bank-gateway-api", Arrays.asList("10.71.136.47", "10.71.137.158"));
        hostMap.put("branch-api-gateway", Arrays.asList("10.71.137.92", "10.71.141.59"));
        hostMap.put("branch-anyapi-server-batch", Arrays.asList("10.71.137.92", "10.71.141.59"));

        // trunk
        hostMap.put("trunk-anyapi-server-api", Arrays.asList("10.71.142.182", "10.71.142.228", "10.71.142.44"));
        hostMap.put("trunk-bank-gateway-api", Arrays.asList("10.71.142.182", "10.71.142.228", "10.71.142.44"));
        hostMap.put("trunk-api-gateway", Arrays.asList("10.71.142.31", "10.71.141.66"));
        hostMap.put("trunk-anyapi-server-batch", Arrays.asList("10.71.142.31", "10.71.141.66"));
    }


    /**
     * 获取文件规则
     */
    public static List<String> typeRules = Arrays.asList(
            "tar.gz"
            , "batch.jar"
            , "1.10.0-RELEASE.jar"
    );
    /**
     * 固定前缀
     */
    public static String localPtah = "D:\\workspace\\";

    /**
     * 本地文件路径
     */
    public static Map<String, String> localFilePathMap = new HashMap<>();

    static {
        localFilePathMap.put("anyapi-server-api", localPtah + "anyapi-server-parent\\anyapi-server-api\\target\\");
        localFilePathMap.put("bank-gateway-api", localPtah + "bank-gateway\\bank-gateway-api\\target\\");
        localFilePathMap.put("api-gateway", localPtah + "api-gateway\\target\\");
        localFilePathMap.put("anyapi-server-batch", localPtah + "anyapi-server-parent\\anyapi-server-batch\\target\\");

    }

    /**
     * 固定前缀
     */
    public static String evn = "branch";
    //public static String evn = "trunk";

    public static List<String> appRules = new ArrayList<>();

    static {
        appRules.add("anyapi-server-api");
        //appRules.add("bank-gateway-api");
        //appRules.add("anyapi-server-batch");
        //appRules.add("api-gateway");
    }

    public static void main(String[] args) throws IOException {

        StopWatch stopWatch = new StopWatch("应用上传部署");
        stopWatch.start();
        String ap = apMap.get(evn);
        String[] split = ap.split("&");
        String remoteUsername = split[0];
        String remotePassword = split[1];


        for (String appRule : appRules) {
            File file = new File(localFilePathMap.get(appRule));
            if (!file.exists()) {
                System.out.println("文件目录不存在");
                return;
            }
            boolean tarGzExtractorFlag = true;
            List<String> fileNames = getFileNames(file, Collections.singletonList(appRule));
            String filePath = fileNames.stream().filter(f -> f.contains(appRule)).findFirst().get();
            for (Map.Entry<String, List<String>> entry : hostMap.entrySet()) {
                String key = entry.getKey();
                boolean contains = key.contains(evn) && key.contains(appRule);
                if (contains) {
                    List<String> hosts = entry.getValue();
                    for (String remoteHost : hosts) {
                        String remoteFolderPath = "/data/apps/";
                        if (key.endsWith("anyapi-server-api") || key.endsWith("api-gateway")) {
                            remoteFolderPath = remoteFolderPath + appRule + "/";
                        } else if (key.endsWith("bank-gateway-api")) {

                            // 解压后的路径
                            String toPath = filePath.substring(0, filePath.lastIndexOf("\\") + 1);
                            if (tarGzExtractorFlag) {
                                // 解压文件
                                tarGzExtractor(filePath, toPath);
                                tarGzExtractorFlag = false;
                            }
                            String cmd = getCmd(remoteFolderPath, appRule);
                           /// jar包上传
                            String remoteFolderLibPath = remoteFolderPath + "bank-gateway/lib/";
                            String libPaths = toPath + "lib\\bank-gateway-dao-1.10.0-RELEASE.jar";
                            libPaths = libPaths + "&" + toPath + "lib\\bank-gateway-mfrs-1.10.0-RELEASE.jar";
                            libPaths = libPaths + "&" + toPath + "lib\\bank-gateway-normal-1.10.0-RELEASE.jar";
                            libPaths = libPaths + "&" + toPath + "lib\\bank-gateway-service-1.10.0-RELEASE.jar";
                            System.out.println("source:" + libPaths);
                            System.out.println("target:" + remoteUsername + "@" + remoteHost + remoteFolderLibPath + " -p:" + remotePassword);
                            uploadFileToLinux(libPaths, remoteUsername, remotePassword, remoteHost, remoteFolderLibPath, "");
                            // classes上传
                            String remoteFolderComPath = remoteFolderPath + "bank-gateway/classes/com";
                            String comPaths = toPath + "classes\\com";
                            System.out.println("source:" + comPaths);
                            System.out.println("target:" + remoteUsername + "@" + remoteHost + remoteFolderComPath + " -p:" + remotePassword);
                            uploadFileToLinux(comPaths, remoteUsername, remotePassword, remoteHost, remoteFolderComPath, cmd);
                        } else if (key.endsWith("anyapi-server-batch")) {
                            String remoteFolderPath1 = remoteFolderPath + appRule + "1011";
                            String remoteFolderPath2 = remoteFolderPath + appRule + "1012";
                            remoteFolderPath = remoteFolderPath1 + "&" + remoteFolderPath2;

                        }
                        if (!key.endsWith("bank-gateway-api")) {
                            String[] remoteFolderPaths = remoteFolderPath.split("&");
                            for (int i = 0; i < remoteFolderPaths.length; i++) {
                                remoteFolderPath = remoteFolderPaths[i];
                                System.out.println("source:" + filePath);
                                System.out.println("target:" + remoteUsername + "@" + remoteHost + remoteFolderPath + " -p:" + remotePassword);
                                String cmd = getCmd(remoteFolderPath, appRule);
                                System.out.println(cmd);
                                uploadFileToLinux(filePath, remoteUsername, remotePassword, remoteHost, remoteFolderPath, cmd);
                            }
                        }
                    }

                }

            }
        }
        stopWatch.stop();
        System.out.println("总耗时：" + stopWatch.getTotalTimeSeconds() + "秒");

    }

    /**
     * 设置cmd命令
     *
     * @param remoteFolderPath
     * @param appRule
     * @return
     */
    private static String getCmd(String remoteFolderPath, String appRule) {
        String deleteCmd = "";
        String restartCmd = "";
        if (appRule.equalsIgnoreCase("anyapi-server-api")) {
            String app = appRule.replaceAll("-server-api", "");
            deleteCmd = "sh " + remoteFolderPath + "bin/" + "delete-" + app + "-tar.sh";
            restartCmd = "sh " + remoteFolderPath + "bin/" + appRule + ".sh restart " + evn;

        } else if (appRule.equalsIgnoreCase("api-gateway")) {
            String tar = "tar -ZXVf " + remoteFolderPath + appRule + "-1.2.0-RELEASE.tar.gz\n";
            deleteCmd = tar + "sh " + remoteFolderPath + "sbin/" + "shutdown.sh";
            restartCmd = "sh " + remoteFolderPath + "sbin/startup.sh restart " + evn;
        } else if (appRule.equalsIgnoreCase("bank-gateway-api")) {
            // /data/apps/bank-gateway/bin/
            deleteCmd = "";
            restartCmd = "sh " + remoteFolderPath + "bank-gateway/bin/bank-gateway-api.sh restart " + evn;
        } else if (appRule.equalsIgnoreCase("anyapi-server-batch")) {
            deleteCmd = "";
            String evnParam = remoteFolderPath.substring(remoteFolderPath.length() - 4);
            restartCmd = "sh " + remoteFolderPath + "/" + "anyapi-batch.sh restart " + evn + evnParam;
        }
        System.out.println("执行删除命令：" + deleteCmd);
        System.out.println("执行启动命令：" + restartCmd);
        String cmd = deleteCmd + "\n" + restartCmd;
        return cmd;
    }

    /**
     * 加压tar.gz包
     *
     * @param filePath 文件路径
     * @param toPath   解压后的文件路径
     */
    private static void tarGzExtractor(String filePath, String toPath) {
        try {
            FileInputStream fis = new FileInputStream(filePath);
            GZIPInputStream gzipInputStream = new GZIPInputStream(new BufferedInputStream(fis));
            TarArchiveInputStream tarInputStream = new TarArchiveInputStream(gzipInputStream);
            TarArchiveEntry entry;
            while ((entry = tarInputStream.getNextTarEntry()) != null) {
                if (entry.isDirectory()) {
                    new File(toPath + entry.getName()).mkdirs();
                } else {
                    byte[] buffer = new byte[1024];
                    BufferedOutputStream outputStream = new BufferedOutputStream(Files.newOutputStream(Paths.get(toPath + entry.getName())));
                    int bytesRead;
                    while ((bytesRead = tarInputStream.read(buffer)) != -1) {
                        outputStream.write(buffer, 0, bytesRead);
                    }
                    outputStream.close();
                }
            }
            tarInputStream.close();
            gzipInputStream.close();
            fis.close();
            System.out.println("解压完成");
        } catch (IOException e) {
            e.printStackTrace();
        }

    }


    /**
     * 上传到服务器
     *
     * @param filePaths        本地文件路径
     * @param remoteUsername   登录服务器用户名
     * @param remotePassword   登录服务器用密码
     * @param remoteHost       登录服务器IP
     * @param remoteFolderPath 服务器路径
     * @param cmd              cmd命令
     */
    private static void uploadFileToLinux(String filePaths, String remoteUsername, String remotePassword, String remoteHost, String remoteFolderPath, String cmd) {
        JSch jsch = new JSch();
        Session session = null;
        ChannelSftp channelSftp = null;
        ChannelExec channelExec = null;
        try {
            session = jsch.getSession(remoteUsername, remoteHost, 22);
            session.setPassword(remotePassword);
            session.setConfig("StrictHostKeyChecking", "no");
            session.connect();

            channelSftp = (ChannelSftp) session.openChannel("sftp");
            channelSftp.connect();

            String[] filePath = filePaths.split("&");
            for (int i = 0; i < filePath.length; i++) {
                getFileAbsolutePath(filePath[i], remoteFolderPath, channelSftp);
            }

            System.out.println("File uploaded successfully.");
            Channel channel = session.openChannel("exec");
            channelExec = (ChannelExec) channel;
            channelExec.setCommand(cmd);
            InputStream in = channel.getInputStream();
            channel.connect();

            StringBuilder sb = new StringBuilder();
            int c;
            while ((c = in.read()) != -1) {
                sb.append((char) c);
            }
            System.out.println("输出的结果是：" + sb.toString());


        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (channelSftp != null && channelSftp.isConnected()) {
                channelSftp.disconnect();
            }
            if (channelExec != null && channelExec.isConnected()) {
                channelExec.disconnect();
            }
            if (session != null && session.isConnected()) {
                session.disconnect();
            }
        }
    }

    /**
     * 获取文件名称
     *
     * @param file
     * @param appRules
     * @return
     */
    private static List<String> getFileNames(File file, List<String> appRules) {
        List<String> list = new ArrayList<>();
        File[] files = file.listFiles();
        assert files != null;
        for (File f : files) {
            if (f.isDirectory()) {
                List<String> fileNames = getFileNames(f, appRules);
                list.addAll(fileNames);
            } else {
                String absolutePath = f.getAbsolutePath();
                boolean typeRule = typeRules.stream().anyMatch(absolutePath::endsWith);
                boolean appRule = appRules.stream().anyMatch(absolutePath::contains);
                if (typeRule && appRule) {
                    list.add(absolutePath);
                }
            }
        }
        return list;
    }

    /**
     * 获取文件名称
     *
     * @param source
     * @param channelSftp
     * @return
     */
    private static void getFileAbsolutePath(String source, String destination, ChannelSftp channelSftp) throws Exception {
        File file = new File(source);
        File[] files = file.listFiles();
        if (Objects.nonNull(files)) {
            for (File f : files) {
                String absolutePath = f.getAbsolutePath();
                if (f.isDirectory()) {
                    getFileAbsolutePath(absolutePath, destination + "/" + f.getName(), channelSftp);
                } else {
                    channelSftp.put(f.getAbsolutePath(), destination);
                }
            }
        } else {
            channelSftp.put(file.getAbsolutePath(), destination);
        }

    }
}